/*
 * MessageQueue
 * 
 * Version information:1.0
 *
 * Date: 19/11/2012
 */
import java.util.concurrent.ConcurrentLinkedQueue;

import javax.swing.JTextArea;

/**
 * @author dv11rlm
 */

public class MessageQueue implements Runnable {
    /*
     * A boolean that if our run function will continue to loop or
     * not.
     */
    private boolean queueLoop;
    /*
     * A linked queue that is thread-safe in case we would want
     * multiple threads sending messages to the queue.
     */
    private final ConcurrentLinkedQueue<MessageQueueData> resultQueue;
    /*
     * A variable in case we want to just have one text-area where we
     * send our messages.
     */
    private JTextArea myTextArea;

    /**
     * Initialize variables and start our run function in a new
     * Thread.
     */
    public MessageQueue() {
	resultQueue = new ConcurrentLinkedQueue<MessageQueueData>();
	queueLoop = true;
	new Thread(this).start();
    }

    /**
     * Initialize variables and start our run function in a new
     * Thread.
     * 
     * @param textArea
     */
    public MessageQueue(JTextArea textArea) {
	resultQueue = new ConcurrentLinkedQueue<MessageQueueData>();
	queueLoop = true;
	myTextArea = textArea;
	new Thread(this).start();
    }

    /**
     * Add message to queue, result will be added to the given
     * textArea.
     * 
     * @param result
     * @param textArea
     */
    public void addResultToQueue(String result, JTextArea textArea) {
	resultQueue.add(new MessageQueueData(result, textArea));
    }

    /**
     * Add message to queue, result will be added to the textArea
     * given in previously given constructor.
     * 
     * @param result
     * @param textArea
     */
    public void addResultToQueue(String result) {
	if (myTextArea == null) {
	    throw new NullPointerException("The text-area isn't initialized");
	}
	resultQueue.add(new MessageQueueData(result, myTextArea));
    }

    @Override
    public void run() {
	/*
	 * Will loop until queueLoop is set to false then the queue
	 * will process the final objects left in queue then it will
	 * shutdown.
	 */
	while (queueLoop || !resultQueue.isEmpty()) {
	    try {
		if (resultQueue.isEmpty()) {
		    // Waits for 200 millis then restart the loop.
		    Thread.sleep(200);
		    continue;
		}
		resultQueue.poll().appendTextToScreen();
	    } catch (InterruptedException e) {
		System.out.println("Thread queue InterruptedException cause: "
			+ e.getCause());
	    }
	}
    }

    /**
     * Sets boolean-loop variable to false.
     */
    public void indicateShutdownMessageQueue() {
	this.queueLoop = false;
    }

    /**
     * Store a message and which text-area the message should be added
     * to.
     * 
     * @author dv11rlm
     * 
     */
    private class MessageQueueData {
	private final String message;
	private final JTextArea textArea;

	/**
	 * Initialize variables needed to use the class.
	 * 
	 * @param message
	 * @param textArea
	 */
	public MessageQueueData(String message, JTextArea textArea) {
	    this.message = message;
	    this.textArea = textArea;
	}

	/**
	 * Append message to text-area.
	 */
	public void appendTextToScreen() {
	    textArea.append("\n" + message);
	}
    }
}
